package thread.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * @program: Multhread
 * @description:
 * @author: zhanghz001
 * @create: 2021-11-01 16:22
 **/
public class AqsLock extends AbstractQueuedSynchronizer {
    public AqsLock(int i) {
        setState(i);
    }
    
    @Override
    protected int tryAcquireShared(int arg) {
        for (; ; ) {
            int available = getState();
            int remaining = available - arg;
            if (remaining < 0 || compareAndSetState(available, remaining)) {
                return remaining;
            }
        }
    }
    
    @Override
    protected boolean tryReleaseShared(int releases) {
        for (; ; ) {
            int current = getState();
            int next = current + releases;
            if (next < current) {
                throw new Error("Maxinum permit count exceeded");
            }
            if (compareAndSetState(current, next)) {
                return true;
            }
        }
    }
    
    protected final boolean tryReleaseShared1(int releases) {
        for (; ; ) {
            int current = getState();
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }
    
    public static void main(String[] args) {
        AqsLock lock = new AqsLock(3);
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                lock.acquireShared(1);
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("ok");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.releaseShared(1);
                }
            }).start();
        }
    }
}
